package com.dyna.core.utils;

import cn.hutool.core.thread.ThreadUtil;
import com.google.common.cache.*;
import lombok.extern.slf4j.Slf4j;

import javax.validation.constraints.NotNull;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * @author zhoucaiwang
 */
@Slf4j
public class GuavaCacheUtil {

    public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(@NotNull Duration duration,
                                                                     @NotNull CacheLoader<K, V> loader) {
        return CacheBuilder.newBuilder()
                // 指定并发级别
                .concurrencyLevel(10)
                // 初始化容量，配合concurrencyLevel做分段锁
                .initialCapacity(16)
                // 缓存最多可以放多少个元素
                .maximumSize(12)
                // 从写入开始的过期时间
                .expireAfterWrite(10L, TimeUnit.SECONDS)
                // 只阻塞当前数据加载线程，其他线程返回旧值
                .refreshAfterWrite(duration)
                // 统计命中率
                .recordStats()
                // 移除元素监听器
                .removalListener(notification -> {
                    // 监听到的元素
                    Object key = notification.getKey();
                    // 移除原因
                    RemovalCause cause = notification.getCause();
                    log.info("元素【{}】, 因为{}被移除了",key,cause);
                })
                // 通过 asyncReloading 实现全异步加载，包括 refreshAfterWrite 被阻塞的加载线程
                .build(CacheLoader.asyncReloading(loader, ThreadUtil.newExecutor())
                );
    }

    public static <K, V> LoadingCache<K, V> buildAsyncReloadingCache(@NotNull Duration duration,
                                                                     @NotNull RemovalListener<K,V> listener,
                                                                     @NotNull CacheLoader<K, V> loader) {
        return CacheBuilder.newBuilder()
                // 指定并发级别
                .concurrencyLevel(10)
                // 初始化容量，配合concurrencyLevel做分段锁
                .initialCapacity(16)
                // 缓存最多可以放多少个元素
                .maximumSize(12)
                // 从写入开始的过期时间
                .expireAfterWrite(10L, TimeUnit.SECONDS)
                // 只阻塞当前数据加载线程，其他线程返回旧值
                .refreshAfterWrite(duration)
                // 统计命中率
                .recordStats()
                // 移除元素监听器
                .removalListener(listener)
                // 通过 asyncReloading 实现全异步加载，包括 refreshAfterWrite 被阻塞的加载线程
                .build(CacheLoader.asyncReloading(loader, ThreadUtil.newExecutor())
                );
    }

}